﻿/*
* Slickflow 工作流引擎遵循LGPL协议，也可联系作者商业授权并获取技术支持；
* 除此之外的使用则视为不正当使用，请您务必避免由此带来的商业版权纠纷。
* 
The Slickflow project.
Copyright (C) 2014  .NET Workflow Engine Library

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, you can access the official
web page about lgpl: https://www.gnu.org/licenses/lgpl.html
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Sharp.Domain.PlatformBoundedContext.UserModule.Aggregates;
using Sharp.Domain.PlatformBoundedContext.WorkFlowModule.Aggregates;
using Sharp.Domain.PlatformBoundedContext.WorkFlowModule.Engine.Common;
using Sharp.Domain.Repositories;

namespace Sharp.Domain.PlatformBoundedContext.WorkFlowModule.Engine.Business.Manager
{
    public interface IProcessInstanceManager
    {
        /// <summary>
        /// 获取最近的流程运行实例
        /// </summary>
        /// <param name="appInstanceID">应用实例ID</param>
        /// <param name="processGUID">流程GUID</param>
        /// <returns>流程实例</returns>
        ProcessInstanceEntity GetProcessInstanceLatest(String appInstanceID,
            String processGUID);

        /// <summary>
        /// 根据GUID获取流程实例数据
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <returns>流程实例</returns>
        ProcessInstanceEntity GetById(int processInstanceID);

        /// <summary>
        /// 根据活动实例查询流程实例
        /// </summary>
        /// <param name="activityInstanceID">活动实例ID</param>
        /// <returns>流程实例实体</returns>
        ProcessInstanceEntity GetByActivity(int activityInstanceID);

        /// <summary>
        /// 获取流程的发起人
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <returns>流程发起人</returns>
        User GetProcessInitiator(int processInstanceID);

        /// <summary>
        /// 获取最近的流程运行实例
        /// </summary>
        /// <param name="appInstanceID">应用实例ID</param>
        /// <param name="processGUID">流程GUID</param>
        /// <returns>流程实例实体</returns>
        ProcessInstanceEntity GetProcessInstanceCurrent(String appInstanceID,
            String processGUID);

        /// <summary>
        /// 根据流程完成状态获取流程实例数据
        /// </summary>
        /// <param name="appInstanceID"></param>
        /// <param name="processGUID"></param>
        /// <returns></returns>
        IEnumerable<ProcessInstanceEntity> GetProcessInstance(String appInstanceID,
            String processGUID);

        /// <summary>
        /// 获取处于运行状态的流程实例
        /// </summary>
        /// <param name="appInstanceID">应用实例ID</param>
        /// <param name="processGUID">流程GUID</param>
        /// <returns>流程实例实体</returns>
        ProcessInstanceEntity GetRunningProcessInstance(string appInstanceID, string processGUID);

        /// <summary>
        /// 判断流程实例是否存在
        /// </summary>
        /// <param name="processGUID">流程GUId</param>
        /// <param name="version">版本</param>
        /// <returns>流程实例记录数</returns>
        Int32 GetProcessInstanceCount(string processGUID, string version);

        /// <summary>
        /// 检查子流程是否结束
        /// </summary>
        /// <param name="activityInstanceID">活动实例ID</param>
        /// <param name="activityGUID">活动GUID</param>

        /// <returns>是否结束标志</returns>
        bool CheckSubProcessInstanceCompleted(int activityInstanceID,
            String activityGUID);

        /// <summary>
        /// 流程数据插入
        /// </summary>
        /// <param name="entity">流程实例实体</param>

        /// <returns>新实例ID</returns>
        Int32 Insert(ProcessInstanceEntity entity);

        /// <summary>
        /// 流程实例更新
        /// </summary>
        /// <param name="entity">实体</param>
        void Update(ProcessInstanceEntity entity);

        /// <summary>
        /// 根据流程定义，创建新的流程实例
        /// </summary>
        /// <param name="runner">运行者</param>
        /// <param name="processEntity">流程定义</param>
        /// <param name="parentProcessInstance">父流程实例</param>
        /// <param name="subProcessNode">子流程节点</param>
        /// <returns>流程实例的ID</returns>
        ProcessInstanceEntity CreateNewProcessInstanceObject(WfAppRunner runner,
            ProcessEntity processEntity,
            ProcessInstanceEntity parentProcessInstance = null,
            ActivityInstanceEntity subProcessNode = null);

        /// <summary>
        /// 流程完成，设置流程的状态为完成
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">运行者</param>
        void Complete(int processInstanceID, WfAppRunner runner);

        /// <summary>
        /// 挂起流程实例
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">运行者</param>
        void Suspend(int processInstanceID,
            WfAppRunner runner);

        /// <summary>
        /// 恢复流程实例
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">运行者</param>
        /// <returns>标识</returns>
        Boolean Resume(int processInstanceID,
            WfAppRunner runner);

        /// <summary>
        /// 恢复子流程
        /// </summary>
        /// <param name="invokedActivityInstanceID">激活活动实例ID</param>
        /// <param name="runner">运行者</param>
        void RecallSubProcess(int invokedActivityInstanceID,
            WfAppRunner runner);

        /// <summary>
        /// 返签流程，将流程状态置为返签，并修改流程未完成标志
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">运行者</param>
        void Reverse(int processInstanceID,
            WfAppRunner currentUser);

        /// <summary>
        /// 流程的取消操作
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">执行者</param>
        /// <returns>设置成功标识</returns>
        bool Cancel(int processInstanceID, WfAppRunner runner);

        /// <summary>
        /// 废弃单据下所有流程的信息
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">执行者</param>
        /// <returns>设置成功标识</returns>
        bool Discard(int processInstanceID, WfAppRunner runner);

        /// <summary>
        /// 流程终止操作
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">执行者</param>
        /// <returns>设置成功标识</returns>
        bool Terminate(int processInstanceID, WfAppRunner runner);

        /// <summary>
        /// 设置流程过期时间
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="overdueDateTime">过期时间</param>
        /// <param name="runner">当前运行用户</param>
        /// <returns>设置成功标识</returns>
        bool SetOverdue(int processInstanceID,
            DateTime overdueDateTime,
            WfAppRunner runner);

        /// <summary>
        /// 删除不正常的流程实例（流程在取消状态，才可以进行删除！）
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        void Delete(int processInstanceID);
    }

    /// <summary>
    /// 流程实例管理者类
    /// </summary>
    public class ProcessInstanceManager : IProcessInstanceManager
    {
        private IProcessInstanceEntityRepository _processInstanceEntityRepository;
        private IActivityInstanceEntityRepository _activityInstanceEntityRepository;
        public ProcessInstanceManager(IRepositoryContext context,
            IProcessInstanceEntityRepository processInstanceEntityRepository,
            IActivityInstanceEntityRepository activityInstanceEntityRepository
            )
        {
            _processInstanceEntityRepository = processInstanceEntityRepository;
            _activityInstanceEntityRepository = activityInstanceEntityRepository;
        }
        #region ProcessInstanceManager 基本数据操作
        /// <summary>
        /// 获取最近的流程运行实例
        /// </summary>
        /// <param name="appInstanceID">应用实例ID</param>
        /// <param name="processGUID">流程GUID</param>
        /// <returns>流程实例</returns>
        public ProcessInstanceEntity GetProcessInstanceLatest(String appInstanceID,
            String processGUID)
        {
            ProcessInstanceEntity entity = null;
            var processInstanceList = GetProcessInstance(appInstanceID, processGUID).ToList();
            if (processInstanceList != null && processInstanceList.Count > 0)
            {
                entity = processInstanceList[0];
            }
            return entity;
        }

        /// <summary>
        /// 根据GUID获取流程实例数据
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <returns>流程实例</returns>
        public ProcessInstanceEntity GetById(int processInstanceID)
        {
            return _processInstanceEntityRepository.Get(processInstanceID);

        }

        /// <summary>
        /// 根据活动实例查询流程实例
        /// </summary>
        /// <param name="activityInstanceID">活动实例ID</param>
        /// <returns>流程实例实体</returns>
        public ProcessInstanceEntity GetByActivity(int activityInstanceID)
        {
            return _activityInstanceEntityRepository.Get(activityInstanceID).ProcessInstance;

            //using (var session = DbFactory.CreateSession())
            //{
            //    var activityInstance = session.GetRepository<ActivityInstanceEntity>().GetByID(activityInstanceID);
            //var processInstance = session.GetRepository<ProcessInstanceEntity>().GetByID(activityInstance.ProcessInstanceID);
            //    return processInstance;
            //}
        }

        /// <summary>
        /// 获取流程的发起人
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <returns>流程发起人</returns>
        public User GetProcessInitiator(int processInstanceID)
        {
            var entity = GetById(processInstanceID);
            var initiator = new User
            {
                Id = entity.CreatedUserId.Value,
                UserName = entity.CreatedUserName
            };
            return initiator;
        }

        /// <summary>
        /// 获取最近的流程运行实例
        /// </summary>
        /// <param name="appInstanceID">应用实例ID</param>
        /// <param name="processGUID">流程GUID</param>
        /// <returns>流程实例实体</returns>
        public ProcessInstanceEntity GetProcessInstanceCurrent(String appInstanceID,
            String processGUID)
        {
            var processInstanceList = GetProcessInstance(appInstanceID, processGUID);

            return processInstanceList.FirstOrDefault();
        }

        /// <summary>
        /// 根据流程完成状态获取流程实例数据
        /// </summary>
        /// <param name="appInstanceID"></param>
        /// <param name="processGUID"></param>
        /// <returns></returns>
        public IEnumerable<ProcessInstanceEntity> GetProcessInstance(String appInstanceID,
            String processGUID)
        {
            //var sql = @"SELECT 
            //                * 
            //            FROM WfProcessInstance 
            //            WHERE AppInstanceID=@appInstanceID 
            //                AND ProcessGUID=@processGUID 
            //                AND RecordStatusInvalid = 0
            //            ORDER BY CreatedDateTime DESC";

            var instanceList = _processInstanceEntityRepository.GetList(e => e.AppInstanceID == appInstanceID
                && e.ProcessGUID == processGUID
                && e.RecordStatusInvalid == 0, "CreatedTime DESC", (int?)null, (string[])null)
                .ToList();
            return instanceList;

        }

        /// <summary>
        /// 获取处于运行状态的流程实例
        /// </summary>
        /// <param name="appInstanceID">应用实例ID</param>
        /// <param name="processGUID">流程GUID</param>
        /// <returns>流程实例实体</returns>
        public ProcessInstanceEntity GetRunningProcessInstance(string appInstanceID, string processGUID)
        {
            //var sql = @"SELECT 
            //                * 
            //            FROM WfProcessInstance
            //            WHERE AppInstanceID=@appInstanceID 
            //                AND ProcessGUID=@processGUID 
            //                AND RecordStatusInvalid=0
            //                AND (ProcessState=1 OR ProcessState=2)
            //            ORDER BY CreatedDateTime DESC";
            var instanceList = _processInstanceEntityRepository.GetList(e => e.AppInstanceID == appInstanceID
                                                                             && e.ProcessGUID == processGUID
                                                                             && e.RecordStatusInvalid == 0
                                                                             && (e.ProcessState ==
                                                                                 ProcessStateEnum.Ready ||
                                                                                 e.ProcessState ==
                                                                                 ProcessStateEnum.Running))
                .OrderByDescending(e => e.CreatedTime);

            var entity = instanceList.FirstOrDefault();

            return entity;
        }

        /// <summary>
        /// 判断流程实例是否存在
        /// </summary>
        /// <param name="processGUID">流程GUId</param>
        /// <param name="version">版本</param>
        /// <returns>流程实例记录数</returns>
        public Int32 GetProcessInstanceCount(string processGUID, string version)
        {
            //var sql = @"SELECT 
            //                COUNT(1) 
            //            FROM WfProcessInstance
            //            WHERE ProcessGUID=@processGUID
            //                AND Version=@version";

            var count = _processInstanceEntityRepository.Count(e => e.ProcessGUID == processGUID
                && e.Version == version);
            return count;

        }

        /// <summary>
        /// 检查子流程是否结束
        /// </summary>
        /// <param name="activityInstanceID">活动实例ID</param>
        /// <param name="activityGUID">活动GUID</param>

        /// <returns>是否结束标志</returns>
        public bool CheckSubProcessInstanceCompleted(int activityInstanceID,
            String activityGUID)
        {
            bool isCompleted = false;
            var list = _processInstanceEntityRepository.GetList(e => e.InvokedActivityInstanceID == activityInstanceID
                && e.InvokedActivityGUID == activityGUID
                && e.RecordStatusInvalid == 0
                && e.ProcessState == ProcessStateEnum.Completed)
                .OrderByDescending(e => e.CreatedTime)
                .ToList();
            if (list.Count == 1) isCompleted = true;

            return isCompleted;
        }


        /// <summary>
        /// 流程数据插入
        /// </summary>
        /// <param name="entity">流程实例实体</param>

        /// <returns>新实例ID</returns>
        public Int32 Insert(ProcessInstanceEntity entity)
        {
            _processInstanceEntityRepository.Add(entity);
            _processInstanceEntityRepository.Context.Commit();

            return entity.Id;
        }

        /// <summary>
        /// 流程实例更新
        /// </summary>
        /// <param name="entity">实体</param>

        public void Update(ProcessInstanceEntity entity)
        {
            _processInstanceEntityRepository.Update(entity);
            _processInstanceEntityRepository.Context.Commit();
        }

        /// <summary>
        /// 根据流程定义，创建新的流程实例
        /// </summary>
        /// <param name="runner">运行者</param>
        /// <param name="processEntity">流程定义</param>
        /// <param name="parentProcessInstance">父流程实例</param>
        /// <param name="subProcessNode">子流程节点</param>
        /// <returns>流程实例的ID</returns>
        public ProcessInstanceEntity CreateNewProcessInstanceObject(WfAppRunner runner,
            ProcessEntity processEntity,
            ProcessInstanceEntity parentProcessInstance = null,
            ActivityInstanceEntity subProcessNode = null)
        {
            ProcessInstanceEntity entity = new ProcessInstanceEntity();
            entity.ProcessGUID = processEntity.ProcessGUID;
            entity.ProcessName = processEntity.ProcessName;
            entity.Version = processEntity.Version;
            entity.AppName = runner.AppName;
            entity.AppInstanceID = runner.AppInstanceID;
            entity.ProcessState = ProcessStateEnum.Running;
            if (parentProcessInstance != null)
            {
                //流程的Parent信息
                entity.ParentProcessInstanceID = parentProcessInstance.Id;
                entity.ParentProcessGUID = parentProcessInstance.ProcessGUID;
                entity.InvokedActivityInstanceID = subProcessNode.Id;
                entity.InvokedActivityGUID = subProcessNode.ActivityGUID;
            }

            //过期时间设置
            if (processEntity.EndType == EventTriggerEnum.Timer)
            {
                entity.OverdueDateTime = CalculateOverdueDateTime(processEntity.EndExpression);
            }
            entity.CreatedUserId = int.Parse(runner.UserID);
            entity.CreatedUserName = runner.UserName;
            entity.CreatedTime = System.DateTime.Now;
            entity.ModifiedUserId = runner.UserID.ToInt();
            entity.LastUpdatedByUserName = runner.UserName;
            entity.ModifiTime = System.DateTime.Now;
            entity.EndedDateTime = (DateTime?)null;

            return entity;
        }

        /// <summary>
        /// 过期时间计算
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <returns>过期时间</returns>
        private DateTime CalculateOverdueDateTime(string expression)
        {
            var newDate = System.DateTime.Now;
            foreach (Match part in Regex.Matches(expression, @"[0-9]+M|[0-9]+D|[0-9]+H|[0-9]+m|"))
            {
                if (part.Success)
                {
                    Match m = Regex.Match(part.Value, @"[0-9]+");
                    if (m.Success)
                    {
                        var type = part.Value.Substring(part.Value.Length - 1);
                        if (type == "M") newDate = newDate.AddMonths(int.Parse(m.Value));
                        if (type == "D") newDate = newDate.AddDays(int.Parse(m.Value));
                        if (type == "H") newDate = newDate.AddHours(int.Parse(m.Value));
                        if (type == "m") newDate = newDate.AddMinutes(int.Parse(m.Value));
                    }
                }
            }
            return newDate;
        }
        #endregion

        #region 流程业务规则处理

        /// <summary>
        /// 流程完成，设置流程的状态为完成
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">运行者</param>
        public void Complete(int processInstanceID, WfAppRunner runner)
        {
            var bEntity = GetById(processInstanceID);
            var processState = bEntity.ProcessState;
            if ((processState | ProcessStateEnum.Running) == ProcessStateEnum.Running)
            {
                bEntity.ProcessState = ProcessStateEnum.Completed;
                bEntity.EndedDateTime = System.DateTime.Now;
                bEntity.EndedByUserID = runner.UserID;
                bEntity.EndedByUserName = runner.UserName;

                _processInstanceEntityRepository.Update(bEntity);
            }
            else
            {
                throw new ProcessInstanceException("流程不在运行状态，不能被完成！");
            }
        }


        /// <summary>
        /// 挂起流程实例
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">运行者</param>

        public void Suspend(int processInstanceID,
            WfAppRunner runner)
        {
            var bEntity = GetById(processInstanceID);
            var processState = bEntity.ProcessState;
            if ((processState | ProcessStateEnum.Running) == ProcessStateEnum.Running)
            {
                bEntity.ProcessState = ProcessStateEnum.Suspended;
                bEntity.ModifiTime = System.DateTime.Now;
                bEntity.ModifiedUserId = runner.UserID.ToInt();
                bEntity.LastUpdatedByUserName = runner.UserName;

                _processInstanceEntityRepository.Update(bEntity);

                _processInstanceEntityRepository.Context.Commit();
            }
            else
            {
                throw new ProcessInstanceException("流程不在运行状态，不能被完成！");
            }
        }

        /// <summary>
        /// 恢复流程实例
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">运行者</param>
        /// <returns>标识</returns>
        public Boolean Resume(int processInstanceID,
            WfAppRunner runner)
        {
            var bEntity = GetById(processInstanceID);
            var processState = bEntity.ProcessState;
            if ((processState | ProcessStateEnum.Suspended) == ProcessStateEnum.Suspended)
            {
                bEntity.ProcessState = ProcessStateEnum.Running;
                bEntity.ModifiTime = System.DateTime.Now;
                bEntity.ModifiedUserId = runner.UserID.ToInt();
                bEntity.LastUpdatedByUserName = runner.UserName;

                _processInstanceEntityRepository.Update(bEntity);
                _processInstanceEntityRepository.Context.Commit();
                return true;
            }
            else
            {
                throw new ProcessInstanceException("流程不在挂起状态，不能被完成！");
            }

        }
        /// <summary>
        /// 恢复子流程
        /// </summary>
        /// <param name="invokedActivityInstanceID">激活活动实例ID</param>
        /// <param name="runner">运行者</param>

        public void RecallSubProcess(int invokedActivityInstanceID,
            WfAppRunner runner)
        {
            //var sql = @"SELECT * FROM WfProcessInstance
            //                    WHERE InvokedActivityInstanceID=@invokedActivityInstanceID 
            //                        AND ProcessState=5
            //                    ORDER BY CreatedDateTime DESC",
            var list = _processInstanceEntityRepository.GetList(e => e.InvokedActivityInstanceID == invokedActivityInstanceID
                && e.ProcessState == ProcessStateEnum.Suspended)
                .OrderByDescending(e => e.CreatedTime)
                .ToList();

            if (list.Count == 1)
            {
                var bEntity = list[0];

                bEntity.ProcessState = ProcessStateEnum.Running;
                bEntity.ModifiTime = System.DateTime.Now;
                bEntity.ModifiedUserId = runner.UserID.ToInt();
                bEntity.LastUpdatedByUserName = runner.UserName;

                _processInstanceEntityRepository.Update(bEntity);
            }
            else
            {
                throw new ProcessInstanceException("流程不在挂起状态，不能被完成！");
            }
        }


        /// <summary>
        /// 返签流程，将流程状态置为返签，并修改流程未完成标志
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">运行者</param>

        public void Reverse(int processInstanceID,
            WfAppRunner currentUser)
        {
            var bEntity = GetById(processInstanceID);
            if (bEntity.ProcessState == ProcessStateEnum.Completed)
            {
                bEntity.ProcessState = ProcessStateEnum.Running;
                bEntity.ModifiedUserId = currentUser.UserID.ToInt();
                bEntity.LastUpdatedByUserName = currentUser.UserName;
                bEntity.ModifiTime = System.DateTime.Now;

                _processInstanceEntityRepository.Update(bEntity);
            }
            else
            {
                throw new ProcessInstanceException("流程不在运行状态，不能被完成！");
            }
        }

        /// <summary>
        /// 流程的取消操作
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">执行者</param>
        /// <returns>设置成功标识</returns>
        public bool Cancel(int processInstanceID, WfAppRunner runner)
        {
            var entity = _processInstanceEntityRepository.Get(processInstanceID);

            if (entity.ProcessState == ProcessStateEnum.Running
                || entity.ProcessState == ProcessStateEnum.Ready
                || entity.ProcessState == ProcessStateEnum.Suspended)
            {
                entity.ProcessState = ProcessStateEnum.Canceled;
                entity.ModifiedUserId = runner.UserID.ToInt();
                entity.LastUpdatedByUserName = runner.UserName;
                entity.ModifiTime = DateTime.Now;

                _processInstanceEntityRepository.Update(entity);
                _processInstanceEntityRepository.Context.Commit();

                return true;
            }
            else
            {
                throw new ProcessInstanceException("流程已经结束，或者已经被取消！");
            }

        }

        /// <summary>
        /// 废弃单据下所有流程的信息
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">执行者</param>
        /// <returns>设置成功标识</returns>
        public bool Discard(int processInstanceID, WfAppRunner runner)
        {
            var entity = _processInstanceEntityRepository.Get(processInstanceID);

            if (entity.ProcessState == ProcessStateEnum.Running
                || entity.ProcessState ==ProcessStateEnum.Ready
                || entity.ProcessState == ProcessStateEnum.Suspended)
            {
                entity.ProcessState = ProcessStateEnum.Discarded;
                entity.RecordStatusInvalid = 1;
                entity.ModifiedUserId = runner.UserID.ToInt();
                entity.LastUpdatedByUserName = runner.UserName;
                entity.ModifiTime = DateTime.Now;

                _processInstanceEntityRepository.Update(entity);
                _processInstanceEntityRepository.Context.Commit();

                return true;
            }
            else
            {
                throw new ProcessInstanceException("流程已经结束，或者已经被取消！");
            }

        }

        /// <summary>
        /// 流程终止操作
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="runner">执行者</param>
        /// <returns>设置成功标识</returns>
        public bool Terminate(int processInstanceID, WfAppRunner runner)
        {
            var entity = _processInstanceEntityRepository.Get(processInstanceID);

            if (entity.ProcessState == ProcessStateEnum.Running
                || entity.ProcessState == ProcessStateEnum.Ready
                || entity.ProcessState == ProcessStateEnum.Suspended)
            {
                entity.ProcessState = ProcessStateEnum.Terminated;
                entity.EndedByUserID = runner.UserID;
                entity.EndedByUserName = runner.UserName;
                entity.EndedDateTime = DateTime.Now;

                _processInstanceEntityRepository.Update(entity);
                _processInstanceEntityRepository.Context.Commit();

                return true;
            }
            else
            {
                throw new ProcessInstanceException("流程已经结束，或者已经被取消！");
            }

        }

        /// <summary>
        /// 设置流程过期时间
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        /// <param name="overdueDateTime">过期时间</param>
        /// <param name="runner">当前运行用户</param>
        /// <returns>设置成功标识</returns>
        public bool SetOverdue(int processInstanceID,
            DateTime overdueDateTime,
            WfAppRunner runner)
        {
            var entity = _processInstanceEntityRepository.Get(processInstanceID);
            if (entity.ProcessState == ProcessStateEnum.Running
                || entity.ProcessState == ProcessStateEnum.Ready
                || entity.ProcessState == ProcessStateEnum.Suspended)
            {
                entity.OverdueDateTime = overdueDateTime;
                entity.ModifiedUserId = runner.UserID.ToInt();
                entity.LastUpdatedByUserName = runner.UserName;
                entity.ModifiTime = DateTime.Now;

                _processInstanceEntityRepository.Update(entity);
                _processInstanceEntityRepository.Context.Commit();

                return true;
            }
            else
            {
                throw new ProcessInstanceException("流程已经结束，或者已经被取消！");
            }

        }

        /// <summary>
        /// 删除不正常的流程实例（流程在取消状态，才可以进行删除！）
        /// </summary>
        /// <param name="processInstanceID">流程实例ID</param>
        public void Delete(int processInstanceID)
        {
            var entity = _processInstanceEntityRepository.Get(processInstanceID);
            if (entity.ProcessState == ProcessStateEnum.Canceled)
            {
                _processInstanceEntityRepository.Remove(entity);
                _processInstanceEntityRepository.Context.Commit();
            }
            else
            {
                throw new ProcessInstanceException("流程只有先取消，才可以删除！");
            }

        }
        #endregion

    }
}
